import Cesium from '../Ces/Cesium'
import WeFontAltas from './WeFontAltas'

function getKey(imagery) {
  const { x, y, level } = imagery

  return JSON.stringify([x, y, level])
}

class WeVectorObjectRender {
  _weGuid
  _collection
  _readyPromise
  _fontAltas: WeFontAltas
  _font
  _ready
  _altasLabelCollection

  visibleTiles

  constructor(options) {
    this._weGuid = Cesium.createGuid()
    this._collection = new Cesium.AssociativeArray()
    this._readyPromise = Cesium.defer()
    const fontAltas = options.fontAltas
    this._ready = false
    if (fontAltas instanceof Promise) {
      const that = this

      fontAltas
        .then((_fontAltas) => {
          that._fontAltas = _fontAltas
          that._font = _fontAltas.font
          that._altasLabelCollection = _fontAltas.NewLabelCollection()
          that._readyPromise.resolve(true)
        })
        .catch(() => {
          that._readyPromise.resolve(false)
        })
    } else {
      if (fontAltas) {
        this._fontAltas = fontAltas
        this._font = fontAltas.font
        this._altasLabelCollection = this._fontAltas.NewLabelCollection()
      } else {
        const scene = options.scene
        this._altasLabelCollection = new Cesium.LabelCollection({
          scene,
        })
      }
      this._readyPromise.resolve(true)
    }

    this.visibleTiles = {}
  }

  get readyPromise() {
    return this._readyPromise.promise
  }

  resetVisible() {
    this.visibleTiles = {}
  }

  filterVisible(imagery) {
    if (imagery.weGuid !== this._weGuid) {
      return
    }

    const cacheKey = getKey(imagery)

    let parentKey

    if (imagery.parent) {
      parentKey = getKey(imagery.parent)
    }

    this.visibleTiles[cacheKey] = parentKey
  }

  addCache(x, y, level, renderObj) {
    const cacheKey = JSON.stringify([x, y, level])
    this._collection.set(cacheKey, renderObj)
  }

  removeCache(x, y, level) {
    const cacheKey = JSON.stringify([x, y, level])
    const renderObj = this._collection.get(cacheKey)

    if (renderObj) {
      renderObj.destroy()
    }
    this._collection.remove(cacheKey)
  }

  requestImage(_x, _y, _level, _request, _imageryLayerProvider) {
    throw new Cesium.DeveloperError('unimplemented')
  }

  update(frameState) {
    const that = this

    const visibleTiles = this.visibleTiles

    const visibleKeys = {}

    let hasProxy = false
    Object.keys(this.visibleTiles).forEach((cacheKey) => {
      let canRender = true
      const parentKey = visibleTiles[cacheKey]

      if (parentKey) {
        canRender = !Cesium.defined(visibleTiles[parentKey])
      }

      visibleKeys[cacheKey] = canRender

      if (canRender) {
        const renderObj = that._collection.get(cacheKey)

        if (renderObj) {
          if (renderObj.update) {
            renderObj.update(frameState)
          } else if (renderObj.updateVisible) {
            hasProxy = true
          }
        }
      }
    })

    if (hasProxy) {
      const keys = Object.keys(this._collection._hash)
      // console.info('renderCount', keys.length)
      for (let i = 0; i < keys.length; i++) {
        const cacheKey = keys[i]
        const visible = Cesium.defined(visibleKeys[cacheKey]) && visibleKeys[cacheKey]
        const renderObj = this._collection.get(cacheKey)
        if (renderObj.updateVisible) {
          renderObj.updateVisible(visible)
        }
      }
    }

    this._altasLabelCollection.update(frameState)
  }

  destroy() {
    for (let i = 0; i < this._collection.length; i++) {
      const renderObj = this._collection.values[i]

      renderObj.destroy()
    }

    return Cesium.destroyObject(this)
  }

  isDestroyed() {
    return false
  }
}

export default WeVectorObjectRender
